package org.kl.bf.repository;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Selection;

import org.apache.commons.lang3.StringUtils;
import org.kl.bf.entity.AttachmentEntity;
import org.kl.bf.entity.AuditableEntity;
import org.kl.bf.entity.IdEntity;
import org.kl.bf.entity.basic.AttachmentMaster;
import org.kl.bf.utils.CRUDUtils;
import org.kl.bf.utils.KLDynamicSpecifications;
import org.kl.bf.web.base.BasicController;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springside.modules.utils.Collections3;

/**
 * {@link BasicRepository}接口实现类，并在{@link PagingAndSortingRepository}基础上扩展。
 * 
 * @Author hqm
 * @CreateTime 2014-3-14 下午5:07:17
 */
@NoRepositoryBean
public class BasicRepositoryImpl<T extends Serializable, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements
		BasicRepository<T, ID> {
	private final EntityManager em;
	private final JpaEntityInformation<T, ?> entityInformation;

	/**
	 * 构造函数
	 * 
	 * @param domainClass
	 * @param em
	 */
	public BasicRepositoryImpl(final JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {

		super(entityInformation, entityManager);
		this.em = entityManager;
		this.entityInformation = entityInformation;
	}

	public BasicRepositoryImpl(Class<T> domainClass, EntityManager em) {
		this(JpaEntityInformationSupport.getMetadata(domainClass, em), em);
	}

	/**
	 * 扩展默认的save方法，加入审计信息
	 */
	public <S extends T> S save(S entity) {
		if (entity instanceof AuditableEntity) {
			AuditableEntity one = (AuditableEntity) entity;
			if (StringUtils.isEmpty(one.getId())) {
				one.setCreateBy(BasicController.getCurrentUserId());
				one.setCreateMan(BasicController.getCurrentUserName());
				one.setCreateTime(new Timestamp(System.currentTimeMillis()));
				one.setCreateDept(BasicController.getCurrentUserDeptId());
				one.setCreateDeptName(BasicController.getCurrentUserDeptName());
			}
		}
		if (entity instanceof AttachmentEntity) {
			AttachmentEntity one = (AttachmentEntity) entity;
			if (one.getAttachmentMaster() == null) {
				AttachmentMaster attachmentMaster = new AttachmentMaster();
				em.persist(attachmentMaster);
				one.setAttachmentMaster(attachmentMaster);
			}
		}
		if (StringUtils.isBlank((String) entityInformation.getId(entity))) {// 如果为新增操作
			if (entity instanceof IdEntity) {
				((IdEntity) entity).setId(null);
			}
			em.persist(entity);
			return entity;
		} else {// 如果为修改该操作
			return em.merge(entity);
		}
	}

	@Override
	public T find(Class<T> clazz, Object pk) {
		T result = em.find(clazz, pk);
		em.clear();
		return result;
	}

	public T sumByKLSearchFilter(CriteriaQuery<T> criteriaQuery, Predicate[] predicates, Selection<?>... selections) {
		criteriaQuery.multiselect(selections);
		if (predicates != null) {
			criteriaQuery.where(predicates);
		}
		List<T> resultList = em.createQuery(criteriaQuery).getResultList();
		if (Collections3.isEmpty(resultList)) {
			return null;
		} else {
			return resultList.get(0);
		}
	}

	@Override
	public T footerByKLSearchFilter(CriteriaQuery<T> criteriaQuery, Predicate[] predicates, Selection<?>... selections) {
		criteriaQuery.multiselect(selections);
		if (predicates != null) {
			criteriaQuery.where(predicates);
		}
		List<T> resultList = em.createQuery(criteriaQuery).getResultList();
		if (Collections3.isEmpty(resultList)) {
			return null;
		} else {
			return resultList.get(0);
		}
	}

	@Override
	public Page<T> getPage(Map<String, Object> searchParams, int pageNumber, int pageSize, String sortType, String orderType, Class<T> clazz) {
		PageRequest pageRequest = CRUDUtils.buildPageRequest(pageNumber, pageSize, sortType, orderType);
		Specification<T> spec = KLDynamicSpecifications.buildSpecification(searchParams, clazz);
		return findAll(spec, pageRequest);
	}

	@Override
	public List<T> searchAll(Map<String, Object> searchParams, Class<T> clazz) {
		Specification<T> spec = KLDynamicSpecifications.buildSpecification(searchParams, clazz);
		return findAll(spec);
	}

	@Override
	public List<T> searchAll(Map<String, Object> searchParams, String sortType, String orderType, Class<T> clazz) {
		Sort sort = CRUDUtils.buildSort(sortType, orderType);
		Specification<T> spec = KLDynamicSpecifications.buildSpecification(searchParams, clazz);
		return findAll(spec, sort);
	}

	public EntityManager getEntityManager() {
		return em;
	}

	public CriteriaBuilder getCriteriaBuilder() {
		return em.getCriteriaBuilder();
	}
}
